package controller;



import java.util.HashMap;
import java.util.Map;

import screens.GameMainScreen.StateGame;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Pool;

import model.Block;
import model.Bob;
import model.Bob.State;
import model.Bullet;
import model.World;

public class BobController {
	enum Keys{
		LEFT, RIGHT, JUMP, FIRE
	}
	
	static final long LONG_JUMP_PRESS =150l;
	static final float ACELERATION =20f;
	static final float GRAVITY =-20f;
	static final float MAX_JUMP_SPEED = 7f;
	static final float DAMP=0.90f;
	static final float MAX_VEL = 4f;
	
	static final float WIDTH =10f;
	WorldController worldControl;
	World world;
	Bob bob;
	long jumpPressedTime;
	boolean jumpingPressed;
	boolean firingPressed=false;
	boolean grounded = false;
	Sound [] soundBob;
	static Map <Keys, Boolean> keys = new HashMap<BobController.Keys, Boolean>();
	Pool<Rectangle> rectPool = new Pool<Rectangle>(){
		@Override
		protected Rectangle newObject(){
			return new Rectangle();
		}
	};
	//collistion
	Array<Block> collidable = new Array<Block>();
	
	static {
		keys.put(Keys.LEFT,false);
		keys.put(Keys.RIGHT, false);
		keys.put(Keys.JUMP, false);
		keys.put(Keys.FIRE, false);
		
	}
	public BobController (WorldController worldControl){
		this.worldControl=worldControl;
		this.world=worldControl.getWorld();
		this.bob = world.getBob();
		initSoundBob();
	}
	public void initSoundBob(){
		soundBob = new Sound[2];
		soundBob[0]=Gdx.audio.newSound(Gdx.files.internal(bob.getSoundJump()));
		soundBob[1]=Gdx.audio.newSound(Gdx.files.internal("sound/fire.mp3"));
		
	}
	// ---key pressed and touch----
	
	public void leftPressed(){
		keys.get(keys.put(Keys.LEFT, true));
	}
	public void rightPressed(){
		keys.get(keys.put(Keys.RIGHT, true));
	}
	public void jumpPressed(){
		keys.get(keys.put(Keys.JUMP, true));
	}
	public void firePressed(){
		keys.get(keys.put(Keys.FIRE , true));
		firingPressed=true;
	}
	public void leftReleased(){
		keys.get(keys.put(Keys.LEFT, false));		
	}
	public void rightReleased(){
		keys.get(keys.put(Keys.RIGHT, false));		
	}
	public void jumpReleased(){
		keys.get(keys.put(Keys.JUMP, false));		
		jumpingPressed=false;
	}
	public void fireReleased(){
		keys.get(keys.put(Keys.FIRE, false));	
		firingPressed=false;
	}
	public World getWorld(){
		return this.world;
	}
	
	//update
	
	public void update(float delta){
		processInput();
		if(bob.getGrounded() &&bob.getState().equals(State.JUMPING)){
			bob.setState(State.IDLE);

		}
		if(bob.getVelocity().y<0)
			bob.setGrounded(false);
		bob.getAcceleration().y =GRAVITY;
		bob.getAcceleration().scl(delta);
		bob.getVelocity().add(bob.getAcceleration().x,bob.getAcceleration().y);
		checkCollisionWithBlocks(delta);
		if(checkCollistionWithDoor()){
			if(!world.nextLevel()){
				worldControl.stopMusic();
				worldControl.setState(StateGame.GAMEEND);
				
			}
			else{
				
				worldControl.musicUpdate();
				
			}
		}
		bob.getVelocity().x*=DAMP;
		if(bob.getVelocity().x>MAX_VEL){
			bob.getVelocity().x= MAX_VEL;
		}
		if(bob.getVelocity().x<-MAX_VEL){
			bob.getVelocity().x=-MAX_VEL;
		}
		bob.update(delta);
		bob.getBounds().x=bob.getPosition().x;
		bob.getBounds().y=bob.getPosition().y;
		
		for(Bullet bullet: bob.getFire()){
			bullet.update(delta);
			if(bullet.isDisapear())
				bob.getFire().removeValue(bullet, false);
		}
		
	}
	
	
	/// change bob state .....
	//
	private void processInput(){

		if(keys.get(Keys.JUMP)){
			if(!bob.getState().equals(State.JUMPING)&&bob.getVelocity().y>=0){
				jumpingPressed= true;
				jumpPressedTime=System.currentTimeMillis();
				bob.setState(State.JUMPING);
				bob.getVelocity().y= MAX_JUMP_SPEED;
				bob.setGrounded(false);
				soundBob[0].play();
			}
			else {
				if(jumpingPressed&&(System.currentTimeMillis()- jumpPressedTime>= LONG_JUMP_PRESS)){
					jumpingPressed = false;
				}
				else{
					if(jumpingPressed){
						bob.getVelocity().y =MAX_JUMP_SPEED;
					}
					
				}
					
			}
		}
		if(keys.get(Keys.LEFT)){
			//left is pressed
			bob.setFacingleft(true);
			if(!bob.getState().equals(State.JUMPING)){
				bob.setState(State.WALKING);
				
			}
			bob.getAcceleration().x=-ACELERATION;
		}
		else if(keys.get(Keys.RIGHT)){
			//right is pressed
			bob.setFacingleft(false);
			if(!bob.getState().equals(State.JUMPING)){
				bob.setState(State.WALKING);
				
			}
			bob.getAcceleration().x=ACELERATION;
		}
		else{ if(!bob.getState().equals(State.JUMPING)){
			bob.setState(State.IDLE);
			
			}
			bob.getAcceleration().x=0;
		}
		if(firingPressed){
			//bob.getFire().add(new Bullet(new Vector2(bob.getPosition().x,bob.getPosition().y),bob.isFacingLeft()));
			bob.Fire();
			soundBob[1].play();
			firingPressed=false;
		}
			
	}
	
	/*private Array<Block> populateCollidableBlocks(int startX,int startY, int endX, int endY){
		Array<Block> collis = new Array<Block>();
		//collidable.clear();
		for(int x= startX; x<=endX;x++){
			for(int y = startY;y<=endY;y++){
				if(x>=0&& x<world.getLevel().getWidth()&&y>=0&&y<world.getLevel().getHeight()){
					//collidable.add(world.getLevel().get(x,y));
					collis.add(world.getLevel().get(x,y));
				}
			}
		}
		return collis;
	}*/
	private boolean checkCollistionWithDoor(){
		if(bob.getBounds().overlaps(world.getDoor().getBounds())){
			return true;
		}
		return false;
	}
	private void checkCollisionWithBlocks(float delta){
		bob.getVelocity().scl(delta);
		Rectangle bobRect = rectPool.obtain();
		bobRect.set(bob.getBounds().x,bob.getBounds().y,bob.getBounds().width,bob.getBounds().height);
		int startX, endX;
		int startY= (int)bob.getBounds().y;
		int endY=(int)(bob.getBounds().y+bob.getBounds().height);
		if(bob.getVelocity().x<0){
			startX=(int)Math.floor(bob.getBounds().x+bob.getVelocity().x);
			endX=(int)Math.floor(bob.getBounds().x);
			if(startX<0){
				startX=0;
			}
		}
		else {
			endX=(int)Math.floor(bob.getBounds().x+bob.getBounds().width+bob.getVelocity().x);
			startX=(int)Math.floor(bob.getBounds().x+bob.getBounds().width);
		}
		collidable=worldControl.populateCollidableBlocks(startX, startY, endX, endY);
		bobRect.x+=bob.getVelocity().x;
		world.getCollistionRects().clear();
		for(Block block: collidable){
			if(block==null) continue;
			if(bob.getVelocity().x<0)
			{
				Block newBlock=new Block(new Vector2(0,0));
				for(Block block1:collidable){
					if(block1!=null)
						newBlock=block1;
					if(block1==null)break;
				}
				bob.getVelocity().x=0;				
				world.getCollistionRects().add(newBlock.getBounds());
				break;
			}
			else
			{
				bob.getVelocity().x=0;			
				world.getCollistionRects().add(block.getBounds());
				break;
			}
			/*if(bobRect.overlaps(block.getBounds())){
				bob.getVelocity().x=0;
				world.getCollistionRects().add(block.getBounds());
				break;
			}*/
		}
		bobRect.x=bob.getPosition().x;
		startX=(int)bob.getBounds().x;
		endX=(int)(bob.getBounds().x+bob.getBounds().width);
		if(bob.getVelocity().y<0){
			startY=(int)Math.floor(bob.getBounds().y +bob.getVelocity().y);
			endY=(int)Math.floor(bob.getBounds().y);
		}
		else {
			endY=(int)Math.floor(bob.getBounds().y+bob.getBounds().height+bob.getVelocity().y);
			startY=(int)Math.floor(bob.getBounds().y+bob.getBounds().height);
		}
		collidable=worldControl.populateCollidableBlocks(startX, startY, endX, endY);
		bobRect.y+=bob.getVelocity().y;
		for(Block block: collidable){
			if(block==null)continue;
			if(bob.getVelocity().y<0)
			{
				Block newBlock=new Block(new Vector2(0,0));
				for(Block block1:collidable){
					if(block1!=null)
						newBlock=block1;
					if(block1==null)break;
				}
				bob.getVelocity().y=0;				
				world.getCollistionRects().add(newBlock.getBounds());
				bob.setGrounded(true);
				break;
			}
			else
			{
				bob.getVelocity().y=0;			
				world.getCollistionRects().add(block.getBounds());
				
				break;
			}
			/*if(bobRect.overlaps(block.getBounds())){
				if(bob.getVelocity().y<0){
					grounded=true;
				}
				bob.getVelocity().y=0;
				world.getCollistionRects().add(block.getBounds());
				break;
			}*/
		}
		bobRect.y=bob.getPosition().y;
		bob.getPosition().add(bob.getVelocity());
		bob.getBounds().x=bob.getPosition().x;
		bob.getBounds().y=bob.getPosition().y;
		bob.getVelocity().scl(1/delta);
			
			
		
	}
	
}
